package org.jet.emall.log;

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.Signature;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.jet.emall.common.constant.CommonMapKey;
import org.jet.emall.rbac.dto.AdminLoginLogDTO;
import org.jet.emall.security.model.UserDetailsModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.time.LocalDateTime;


/**
 * @author xiaozai
 * @version 1.0
 * @date 2020-04-14 17:52
 */
@Aspect
@Component
public class LoginLogAspect {
    @Autowired
    private ThreadPoolUtil threadPoolUtil;

    private Logger log = LoggerFactory.getLogger(getClass());

    /**
     *  这个切点会切在登录成功处理器的回调方法上
     */
    @Pointcut(value = "@annotation(org.jet.emall.log.AdminLoginLog)")
    public void cutService() {
    }

    // 切在登录成功处理器的回调方法之前
    @Before("cutService()")
    public void recordSysLog(JoinPoint point) throws Throwable {
        handle(point);
    }


    private void handle(JoinPoint point) throws Throwable {

        LocalDateTime beginDateTime = LocalDateTime.now();

        // 接收到请求，记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        //获取拦截的方法名
        Signature sig = point.getSignature();
        MethodSignature msig = null;
        if (!(sig instanceof MethodSignature)) {
            throw new IllegalArgumentException("该注解只能用于方法");
        }
        msig = (MethodSignature) sig;
        Object target = point.getTarget();
        Method currentMethod = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
        AdminLoginLog annotation = currentMethod.getAnnotation(AdminLoginLog.class);

        if(log.isDebugEnabled()) {
            log.debug("Authen=" + SecurityContextHolder.getContext().getAuthentication());
        }
        Integer userId = null;
        String username = null;
        Integer roleId = null;
        String roleName = null;

        // 如果是登录请求，则我们的TokenAuthenticationFilter不可能从请求头中取出token,所以登录之后只能在安全上下文中取
        if (annotation.value() == LogType.LOGIN) {
            UserDetailsModel userDetailsModel = (UserDetailsModel) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
            userId = userDetailsModel.getId();
            username = userDetailsModel.getUsername();
            roleId = userDetailsModel.getRoleId();
            roleName = userDetailsModel.getAuthorities().iterator().next().getAuthority();
        } else {
            // 登出请求的话是带有token的,我们的TokenAuthenticationFilter会从中取token,然后放四个数据到请求的Attributes中
            userId = (Integer) request.getAttribute(CommonMapKey.USER_ID_KEY);
            username = (String) request.getAttribute(CommonMapKey.USER_NAME_KEY);
            roleId = (Integer) request.getAttribute(CommonMapKey.ROLE_ID_KEY);
            roleName = (String) request.getAttribute(CommonMapKey.ROLE_NAME_KEY);
        }
        String ip = request.getRemoteAddr();
        String userAgent = request.getHeader("User-Agent");

        AdminLoginLogDTO loginLog = LogFactory.createLoginLog(userId, username, roleId, roleName, ip, userAgent, annotation.value(), beginDateTime);
        threadPoolUtil.addTask(loginLog);
    }
}
